﻿#ifndef SRC_UTIL_MD5_H_
#define SRC_UTIL_MD5_H_

#include <string>
#include <iostream>
#include <cstdint>

namespace toolkit {

// 一个用于计算字符串或字节数组的 MD5 哈希值的小型类
// 它不是为了快速或安全而设计的
//
// 用法: 1) 通过 update() 提供 uchar 块
//      2) finalize()
//      3) 获取 hexdigest() 字符串
//      或者
//      MD5(std::string).hexdigest()
//
// 假设 char 是 8 位的，int 是 32 位的
class Md5
{
public:
    typedef unsigned int sizeType; // 必须是 32 位

    Md5();
    Md5(const std::string& text);
    void update(const unsigned char *buf, sizeType length);
    void update(const char *buf, sizeType length);
    Md5& finalize();
    std::string hexDigest() const;
    std::string rawDigest() const;
    friend std::ostream& operator<<(std::ostream&, Md5 md5);
private:
    void init();
    typedef uint8_t uint1; // 8 位
    typedef uint32_t uint4; // 32 位
    enum {blockSize = 64}; // VC6 不接受这里的 const static int

    void transform(const uint1 block[blockSize]);
    static void decode(uint4 output[], const uint1 input[], sizeType len);
    static void encode(uint1 output[], const uint4 input[], sizeType len);

    bool finalized;
    uint1 buffer[blockSize]; // 不适合最后 64 字节块的字节
    uint4 count[2];   // 位数的 64 位计数器 (lo, hi)
    uint4 state[4];   // 到目前为止的摘要
    uint1 digest[16]; // 结果

    // 低级逻辑操作
    static inline uint4 f(uint4 x, uint4 y, uint4 z);
    static inline uint4 g(uint4 x, uint4 y, uint4 z);
    static inline uint4 h(uint4 x, uint4 y, uint4 z);
    static inline uint4 i(uint4 x, uint4 y, uint4 z);
    static inline uint4 rotateLeft(uint4 x, int n);
    static inline void ff(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
    static inline void gg(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
    static inline void hh(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
    static inline void ii(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac);
};

std::string md5(const std::string str);
} /* namespace toolkit */

#endif /* SRC_UTIL_MD5_H_ */
